package start.spring.basic.filter;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.zip.GZIPInputStream;

import org.apache.commons.io.IOUtils;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;

import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * 
 * ****************************************************************************
 * response日志记录
 *
 * @author(作者)：xuyongyun
 * @date(创建日期)：2023年2月2日
 ******************************************************************************
 */
@Slf4j
@Component
public class HttpResponseFilter extends BaseFilter implements GlobalFilter, Ordered {
	
	@Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		//后置处理
		boolean isRecode = true;
		
        ServerHttpRequest request = exchange.getRequest();
        
        String uri = request.getURI().getPath();
        String method = request.getMethodValue();
        
        //返回链路traceId用于请求追踪
        String traceId = request.getHeaders().getFirst(super.REQUEST_KEY_TRACEID);
        
        //校验是否静态资源
        for(int i=0;i<super.EXCLUDE_STATIC.length;i++) {
        	//静态资源直接跳过验证
			if(uri.indexOf(super.EXCLUDE_STATIC[i])>0) {
				isRecode = false;
				break;
			}
		}
      
        if(isRecode) {
        	
            //不需要记录请求结果的url关键字
            if(super.REQUEST_POST.equals(method)) {
            	for(String denyKeyRequest:super.RESPONSE_KEY_NODETAIL) {
            		if(uri.toLowerCase().equals(denyKeyRequest)) {
            			isRecode = false;
            			break;
	            	}
            	}
            }
            
        	if(isRecode) {
        		ServerHttpResponse originalResponse = exchange.getResponse();
        		
                DataBufferFactory bufferFactory = originalResponse.bufferFactory();
                ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
                    @Override
                    public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                        if (body instanceof Flux) {
                            Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                            return super.writeWith(fluxBody.buffer().map(dataBuffer -> {
                                DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                                DataBuffer join = dataBufferFactory.join(dataBuffer);
                                byte[] content = new byte[join.readableByteCount()];
                                join.read(content);
                                //释放掉内存
                                DataBufferUtils.release(join);
                                String responseData = new String(content, StandardCharsets.UTF_8);
                                List<String> responseHeaders = exchange.getResponse().getHeaders().get(HttpHeaders.CONTENT_ENCODING);
                                if (!CollectionUtils.isEmpty(responseHeaders) 
                                		&& responseHeaders.contains("gzip")) {
                                    GZIPInputStream gzipInputStream = null;
                                    try {
                                        gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(content), content.length);
                                        StringWriter writer = new StringWriter();
                                        IOUtils.copy(gzipInputStream, writer, "UTF-8");
                                        responseData = writer.toString();
                                    } catch (IOException e) {
                                        log.error("====Gzip IO error", e);
                                    } finally {
                                        if (gzipInputStream != null) {
                                            try {
                                                gzipInputStream.close();
                                            } catch (IOException e) {
                                                log.error("===Gzip IO close error", e);
                                            }
                                        }
                                    }
                                } else {
                                	responseData = new String(content, StandardCharsets.UTF_8);
                                }
                                log.info("[{}]:response data: {}", traceId, responseData);//打印请求响应值
                                return bufferFactory.wrap(content);
                            }));
                        }
                        return super.writeWith(body);
                    }
                };
                return chain.filter(exchange.mutate().response(decoratedResponse).build());
        	}
        }
		return chain.filter(exchange);
    }
    
    //顺序,数值越小,优先级越高
    @Override
    public int getOrder() {
        return -200;
    }

}
